/*
 * Copyright (c) 2018, apexes.net. All rights reserved.
 *
 *         http://www.apexes.net
 *
 */
package net.apexes.commons.json.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import net.apexes.commons.lang.Enume;
import net.apexes.commons.lang.EnumeRegistry;

import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;

/**
 * @author <a href="mailto:hedyn@foxmail.com">HeDYn</a>
 */
public final class Gsons {
    private Gsons() {}

    public static final GsonBuilder defaultGsonBuilder = new GsonBuilder();

    public static Gson createGson() {
        return defaultGsonBuilder.create();
    }

    public static GsonBuilder forDefault(EnumeRegistry enumeRegistry) {
        return forDefault(enumeRegistry.getEnumeClasses());
    }

    public static GsonBuilder forDefault(Collection<Class<? extends Enume<?>>> enumeClasses) {
        return register(defaultGsonBuilder, enumeClasses);
    }
    
    public static GsonBuilder createGsonBuilder(EnumeRegistry enumeRegistry) {
        return createGsonBuilder(enumeRegistry.getEnumeClasses());
    }
    
    public static GsonBuilder createGsonBuilder(Collection<Class<? extends Enume<?>>> enumeClasses) {
        return register(new GsonBuilder(), enumeClasses);
    }
    
    public static GsonBuilder register(GsonBuilder gsonBuilder, EnumeRegistry enumeRegistry) {
        return register(gsonBuilder, enumeRegistry.getEnumeClasses());
    }
    
    public static GsonBuilder register(GsonBuilder gsonBuilder, Collection<Class<? extends Enume<?>>> enumeClasses) {
        for (Class<? extends Enume<?>> enumeClass : enumeClasses) {
            register(gsonBuilder, enumeClass);
        }
        return gsonBuilder;
    }
    
    public static GsonBuilder register(GsonBuilder gsonBuilder, Class<? extends Enume<?>> enumeClass) {
        Class<?> valueClass = Enume.valueClass(enumeClass);
        if (valueClass == String.class) {
            Class<Enume<String>> classType = (Class<Enume<String>>) enumeClass;
            return gsonBuilder.registerTypeAdapter(classType, new EnumeByStringAdapter<>(classType));
        }
        if (valueClass == Integer.class) {
            Class<Enume<Integer>> classType = (Class<Enume<Integer>>) enumeClass;
            return gsonBuilder.registerTypeAdapter(classType, new EnumeByIntegerAdapter<>(classType));
        }
        throw new IllegalArgumentException("value only be String or Integer.");
    }

    public static <E> Type createListType(Class<E> elementClass) {
        return TypeToken.getParameterized(List.class, elementClass).getType();
    }
}
